/**
 * 统一的错误处理工具
 * 
 * 提供结构化的错误处理、日志记录和上下文信息保存
 */

import { logger } from './logger.js';

/**
 * 错误上下文信息
 */
export interface ErrorContext {
  /** 操作名称 */
  operation: string;
  /** 相关资源ID或名称 */
  resource?: string;
  /** 用户输入或参数 */
  input?: any;
  /** 额外的上下文数据 */
  metadata?: Record<string, any>;
  /** 相关的用户ID或会话ID */
  userId?: string;
  /** 组件或模块名称 */
  component?: string;
}

/**
 * 结构化的错误信息
 */
export interface StructuredError extends Error {
  /** 错误代码 */
  code?: string;
  /** 错误上下文 */
  context?: ErrorContext;
  /** 原始错误 */
  cause?: Error;
  /** 时间戳 */
  timestamp?: string;
  /** 是否为可恢复错误 */
  recoverable?: boolean;
}

/**
 * 错误类型枚举
 */
export enum ErrorType {
  VALIDATION = 'VALIDATION_ERROR',
  NETWORK = 'NETWORK_ERROR',
  FILE_SYSTEM = 'FILE_SYSTEM_ERROR',
  DATABASE = 'DATABASE_ERROR',
  AUTHENTICATION = 'AUTHENTICATION_ERROR',
  AUTHORIZATION = 'AUTHORIZATION_ERROR',
  EXTERNAL_API = 'EXTERNAL_API_ERROR',
  CONFIGURATION = 'CONFIGURATION_ERROR',
  BUSINESS_LOGIC = 'BUSINESS_LOGIC_ERROR',
  INTERNAL = 'INTERNAL_ERROR',
  TIMEOUT = 'TIMEOUT_ERROR',
  RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND',
}

/**
 * 创建结构化错误
 */
export function createError(
  message: string,
  type: ErrorType = ErrorType.INTERNAL,
  context?: ErrorContext,
  cause?: Error
): StructuredError {
  const error = new Error(message) as StructuredError;
  error.name = type;
  error.code = type;
  error.context = context;
  error.cause = cause;
  error.timestamp = new Date().toISOString();
  error.recoverable = isRecoverableErrorType(type);

  // 如果有原始错误，保留其堆栈信息
  if (cause?.stack) {
    error.stack = `${error.stack}\nCaused by: ${cause.stack}`;
  }

  return error;
}

/**
 * 判断错误类型是否可恢复
 */
function isRecoverableErrorType(type: ErrorType): boolean {
  const recoverableTypes = [
    ErrorType.NETWORK,
    ErrorType.TIMEOUT,
    ErrorType.EXTERNAL_API,
  ];
  return recoverableTypes.includes(type);
}

/**
 * 错误处理器类
 */
export class ErrorHandler {
  /**
   * 记录并处理错误
   */
  static handle(
    error: Error | StructuredError,
    context?: ErrorContext,
    shouldThrow: boolean = true
  ): StructuredError {
    const structuredError = this.ensureStructuredError(error, context);
    this.logError(structuredError);

    if (shouldThrow) {
      throw structuredError;
    }

    return structuredError;
  }

  /**
   * 包装异步函数，自动处理错误
   */
  static async wrapAsync<T>(
    operation: () => Promise<T>,
    context: ErrorContext,
    errorType: ErrorType = ErrorType.INTERNAL
  ): Promise<T> {
    try {
      const result = await operation();
      logger.debug(`Operation completed successfully`, { 
        operation: context.operation,
        component: context.component 
      });
      return result;
    } catch (error) {
      const structuredError = createError(
        `Operation failed: ${context.operation}`,
        errorType,
        context,
        error as Error
      );
      throw this.handle(structuredError, undefined, true);
    }
  }

  /**
   * 包装同步函数，自动处理错误
   */
  static wrap<T>(
    operation: () => T,
    context: ErrorContext,
    errorType: ErrorType = ErrorType.INTERNAL
  ): T {
    try {
      const result = operation();
      logger.debug(`Operation completed successfully`, { 
        operation: context.operation,
        component: context.component 
      });
      return result;
    } catch (error) {
      const structuredError = createError(
        `Operation failed: ${context.operation}`,
        errorType,
        context,
        error as Error
      );
      throw this.handle(structuredError, undefined, true);
    }
  }

  /**
   * 确保错误是结构化的
   */
  private static ensureStructuredError(
    error: Error | StructuredError,
    context?: ErrorContext
  ): StructuredError {
    if (this.isStructuredError(error)) {
      // 如果提供了额外的上下文，合并它
      if (context) {
        error.context = { ...error.context, ...context };
      }
      return error;
    }

    // 转换为结构化错误
    return createError(
      error.message || 'Unknown error occurred',
      ErrorType.INTERNAL,
      context,
      error
    );
  }

  /**
   * 检查是否为结构化错误
   */
  private static isStructuredError(error: any): error is StructuredError {
    return error && typeof error === 'object' && error.context !== undefined;
  }

  /**
   * 记录错误到日志
   */
  private static logError(error: StructuredError): void {
    const logData = {
      message: error.message,
      code: error.code,
      name: error.name,
      timestamp: error.timestamp,
      recoverable: error.recoverable,
      context: error.context,
      stack: error.stack,
      cause: error.cause ? {
        message: error.cause.message,
        name: error.cause.name,
        stack: error.cause.stack,
      } : undefined,
    };

    // 根据错误类型和是否可恢复来决定日志级别
    if (error.recoverable) {
      logger.warn(`Recoverable error occurred`, logData);
    } else {
      logger.error(`Error occurred`, logData);
    }
  }

  /**
   * 从错误中提取用户友好的消息
   */
  static getUserFriendlyMessage(error: Error | StructuredError): string {
    if (this.isStructuredError(error)) {
      switch (error.code) {
        case ErrorType.VALIDATION:
          return '输入数据验证失败，请检查您的输入';
        case ErrorType.NETWORK:
          return '网络连接失败，请稍后重试';
        case ErrorType.TIMEOUT:
          return '操作超时，请稍后重试';
        case ErrorType.AUTHENTICATION:
          return '身份验证失败，请检查您的凭据';
        case ErrorType.AUTHORIZATION:
          return '您没有权限执行此操作';
        case ErrorType.RESOURCE_NOT_FOUND:
          return '请求的资源不存在';
        case ErrorType.EXTERNAL_API:
          return '外部服务暂时不可用，请稍后重试';
        case ErrorType.CONFIGURATION:
          return '配置错误，请联系系统管理员';
        default:
          return error.message || '发生未知错误';
      }
    }

    return error.message || '发生未知错误';
  }

  /**
   * 检查错误是否可重试
   */
  static isRetryable(error: Error | StructuredError): boolean {
    if (this.isStructuredError(error)) {
      return error.recoverable === true;
    }

    // 对于非结构化错误，检查常见的可重试模式
    const message = error.message?.toLowerCase() || '';
    const retryablePatterns = [
      'timeout',
      'network',
      'connection',
      'temporary',
      'rate limit',
      'service unavailable',
      'try again',
    ];

    return retryablePatterns.some(pattern => message.includes(pattern));
  }

  /**
   * 创建操作上下文的便捷方法
   */
  static createContext(
    operation: string,
    component?: string,
    resource?: string,
    metadata?: Record<string, any>
  ): ErrorContext {
    return {
      operation,
      component,
      resource,
      metadata,
      timestamp: new Date().toISOString(),
    } as ErrorContext & { timestamp: string };
  }
}

/**
 * 便捷的错误创建函数
 */
export const createValidationError = (message: string, context?: ErrorContext, cause?: Error) =>
  createError(message, ErrorType.VALIDATION, context, cause);

export const createNetworkError = (message: string, context?: ErrorContext, cause?: Error) =>
  createError(message, ErrorType.NETWORK, context, cause);

export const createFileSystemError = (message: string, context?: ErrorContext, cause?: Error) =>
  createError(message, ErrorType.FILE_SYSTEM, context, cause);

export const createExternalApiError = (message: string, context?: ErrorContext, cause?: Error) =>
  createError(message, ErrorType.EXTERNAL_API, context, cause);

export const createTimeoutError = (message: string, context?: ErrorContext, cause?: Error) =>
  createError(message, ErrorType.TIMEOUT, context, cause);

export const createResourceNotFoundError = (message: string, context?: ErrorContext, cause?: Error) =>
  createError(message, ErrorType.RESOURCE_NOT_FOUND, context, cause);

/**
 * 装饰器：自动错误处理
 * 使用方式：@handleErrors('操作名称', 'ComponentName')
 */
export function handleErrors(operation: string, component?: string) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = async function (...args: any[]) {
      const context = ErrorHandler.createContext(operation, component);
      try {
        const result = await originalMethod.apply(this, args);
        return result;
      } catch (error) {
        throw ErrorHandler.handle(error as Error, context, true);
      }
    };

    return descriptor;
  };
}
